using System;
using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using Sirenix.Utilities.Editor;
using UnityEditor;
using UnityEngine;

public class CustomMenuTree<T>
{
    private OdinEditorWindow _editorWindow;
    private float _menuWidth;
    private float _menuHeight;
    private List<string> _selectedItems = new List<string>();
    private OdinMenuTree _menuTree = new OdinMenuTree();
    private object _trySelectObject;
    public bool IsDirty;
    private Dictionary<string, T> _menuData = new Dictionary<string, T>();
    public CustomMenuTree(OdinEditorWindow parentWindow, Dictionary<string, T> menuData , float menuWidth = 180 , float height = 400)
    {
        this._menuData = menuData;
        this._editorWindow = parentWindow;
        this._menuWidth = menuWidth;
        this._menuHeight = height;
        
        if (UnityEditorEventUtility.HasOnProjectChanged)
        {
            UnityEditorEventUtility.OnProjectChanged -= new Action(this.ProjectWindowChanged);
            UnityEditorEventUtility.OnProjectChanged += new Action(this.ProjectWindowChanged);
        }
        else
        {
            EditorApplication.projectWindowChanged -= new EditorApplication.CallbackFunction(this.ProjectWindowChanged);
            EditorApplication.projectWindowChanged += new EditorApplication.CallbackFunction(this.ProjectWindowChanged);
        }
        this.IsDirty = false;
    }

    public void SetMenuData(Dictionary<string, T> menuData)
    {
        this._menuData = menuData;
        IsDirty = true;
    }

    public void SelectMenuItem(string menuKey)
    {
        _selectedItems.Clear();
        _selectedItems.Add(menuKey);
        foreach (OdinMenuItem odinMenuItem in this._menuTree.EnumerateTree())
        {
            if (this._selectedItems.Contains(odinMenuItem.GetFullPath()))
            {
                odinMenuItem.Select(false);
                _menuTree.ScrollToMenuItem(odinMenuItem);
            }
        }
    }
    private void ProjectWindowChanged() => this.IsDirty = true;
    public void TrySelectMenuItemWithObject(object obj) => this._trySelectObject = obj;

    public IEnumerable<object> GetTargets()
    {
        if (this._menuTree != null)
        {
            for (int i = 0; i < this._menuTree.Selection.Count; ++i)
            {
                OdinMenuItem odinMenuItem = this._menuTree.Selection[i];
                if (odinMenuItem != null)
                {
                    object target = odinMenuItem.Value;
                    if (target is Func<object> func)
                        target = func();
                    if (target != null)
                        yield return target;
                }
            }
        }
    }
    
    public void DrawMenu()
    {
        if (this._trySelectObject != null && this._menuTree != null)
        {
            OdinMenuItem odinMenuItem = this._menuTree.EnumerateTree().FirstOrDefault<OdinMenuItem>((Func<OdinMenuItem, bool>) (x => x.Value == this._trySelectObject));
            if (odinMenuItem != null)
            {
                this._menuTree.Selection.Clear();
                odinMenuItem.Select();
                this._trySelectObject = (object) null;
            }
        }
        GUILayout.BeginArea(new Rect(0, 0, this._menuWidth, _menuHeight));
        // GUILayout.BeginHorizontal(GUILayout.MaxWidth(400));
        GUILayout.BeginVertical();
        Rect currentLayoutRect = GUIHelper.GetCurrentLayoutRect();
        EditorGUI.DrawRect(currentLayoutRect, SirenixGUIStyles.MenuBackgroundColor);
        // Rect rect = new Rect(currentLayoutRect.xMax - 4f, currentLayoutRect.yMin, 4f, currentLayoutRect.height);
 
        // EditorGUIUtility.AddCursorRect(rect, MouseCursor.ResizeHorizontal);
        // this.MenuWidth += SirenixEditorGUI.SlideRect(rect).x;
        foreach (var menuDataItem in _menuData)
        {
            var customMenuItem = new CustomMenuItem<T>(_menuTree,menuDataItem.Key, menuDataItem.Value);
            _menuTree.AddMenuItemAtPath("", customMenuItem);
            // _menuTree.Add(menuDataItem.Key, menuDataItem.Value);
        }
        
        if (IsDirty)
        {
            ForceMenuTreeRebuild();
        }

        if (_menuTree != null)
        {
            _menuTree.DrawSearchToolbar();
            _menuTree.DefaultMenuStyle.SetSelectedColorLightSkin(new Color(0.243f, 0.49f, 0.9f, 0.5f));
            _menuTree.DrawMenuTree();
            OdinMenuTree.ActiveMenuTree = _menuTree;
            GUILayout.EndVertical();
            // GUILayout.BeginVertical();
            // EditorGUI.DrawRect(GUIHelper.GetCurrentLayoutRect(), SirenixGUIStyles.DarkEditorBackground);
            // GUILayout.EndVertical();
            // GUILayout.EndHorizontal();
            GUILayout.EndArea();
            if (this._menuTree != null)
                this._menuTree.HandleKeyboardMenuNavigation();
        }

        _editorWindow.RepaintIfRequested();
    }
    
    public void ForceMenuTreeRebuild()
    {
        if (this._selectedItems.Count == 0 && this._menuTree.Selection.Count == 0)
        {
            OdinMenuItem odinMenuItem = this._menuTree.EnumerateTree().FirstOrDefault<OdinMenuItem>((Func<OdinMenuItem, bool>) (x => x.Value != null));
            if (odinMenuItem != null)
            {
                odinMenuItem.GetParentMenuItemsRecursive(false).ForEach<OdinMenuItem>((Action<OdinMenuItem>) (x => x.Toggled = true));
                odinMenuItem.Select();
            }
        }
        else if (this._menuTree.Selection.Count == 0 && this._selectedItems.Count > 0)
        {
            foreach (OdinMenuItem odinMenuItem in this._menuTree.EnumerateTree())
            {
                if (this._selectedItems.Contains(odinMenuItem.GetFullPath()))
                    odinMenuItem.Select(true);
            }
        }
        this._menuTree.Selection.SelectionChanged += new Action<SelectionChangedType>(this.OnSelectionChanged);
    }
    
    private void OnSelectionChanged(SelectionChangedType type)
    {
        _editorWindow.Repaint();
        GUIHelper.RemoveFocusControl();
        this._selectedItems = _menuTree.Selection.Select<OdinMenuItem, string>((Func<OdinMenuItem, string>) (x => x.GetFullPath())).ToList<string>();
        EditorUtility.SetDirty(_editorWindow);
        IsDirty = true;
    }
}